{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<center>\n",
    "<img src=\"../../img/ods_stickers.jpg\">\n",
    "## Открытый курс по машинному обучению. Сессия № 2\n",
    "\n",
    "### <center> Автор материала: Липко Иван Юрьевич (slack @ivanlipko)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## <center> Индивидуальный проект по анализу данных </center>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "from matplotlib import pyplot as plt\n",
    "%matplotlib inline\n",
    "\n",
    "import json\n",
    "import seaborn as sns"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  Часть 1. Описание набора данных и признаков"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "**1. Описание набора данных и признаков (2 балла)**\n",
    "    (+) Описан процесс сбора данных (если применимо), есть подробное описание решаемой задачи, в чем ее ценность, дано описание целевого и прочих признаков;\n",
    "    (+/-) Сказано, какая задача решается, откуда данные, что есть целевой признак. Даны названия признаков;\n",
    "    (-/+) Сказано, какая задача решается, откуда данные и что есть целевой признак;\n",
    "    (-) Описание отсутствует и дано только название датасета или решаемой задачи, скажем, \"прогноз оттока\".\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "Данные представляют собой **базу кинофильмов и оценок пользователей** из The Movie Database (TMDb). Данные взяты из Kaggle (https://www.kaggle.com/tmdb/tmdb-movie-metadata).\n",
    "\n",
    "Из описания известно что **данные были введены пользователями вручную**, соответственно могут быть ошибки или не соответствия с официальными источниками (All fields are filled out by users so don't expect them to agree on keywords, genres, ratings, or the like). **Метаданные были скачаны** с использованием парсера используя API TMDb's  (https://gist.github.com/SohierDane/4a84cb96d220fc4791f52562be37968b). Как считается рейтинг (целевая переменная), нашёл вот что: \n",
    "` Популярной возможностью IMDb являются онлайн-голосования. Любой зарегистрированный посетитель сайта может голосовать за фильмы, выставляя им рейтинг: от 1 («ужасный фильм» ) до 10 («шедевр» ) баллов `\n",
    "\n",
    "Я **решаю задачу предсказания рейтинга фильма** (признак vote_average). **Ценность** заключается в следующем: можно выяснить, как зависит окупаемость фильма, его популярность, делать подбор актёров таким образом, чтобы рейтинг фильма. Хочу понять, возможно ли предсказать рейтинг фильма, зная только его краткое описание, бюджет и другие общедоступные данные.\n",
    "\n",
    "Описание признаков:\n",
    "\n",
    " - budget -- бюджет фильма (доллары)\n",
    " - genres -- жанр фильма\n",
    " - homepage -- сайт фильма\n",
    " - id -- номер фильма в каталоге\n",
    " - keywords -- ключевые слова\n",
    " - original_language -- оригинальный язык фильма\n",
    " - original_title -- оригинальное название\n",
    " - overview -- краткая аннотация-описание\n",
    " - popularity -- популярность\n",
    " - production_companies -- студия производства\n",
    " - production_countries -- страна-производитель\n",
    " - release_date  -- дата производства (год - месяц - день)\n",
    " - revenue -- доход, кассовый сбор (доллары)\n",
    " - runtime -- продолжительность в минутах\n",
    " - spoken_languages -- языки фильма\n",
    " - status -- статус, вышел фильм или нет\n",
    " - tagline -- Слоган\n",
    " - title -- финальное название фильма\n",
    " - vote_average **(целевой признак)** -- средний рейтинг фильма\n",
    " - vote_count -- количество голосов\n",
    " "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def load_tmdb_movies(path):\n",
    "    df = pd.read_csv(path)\n",
    "    df['release_date'] = pd.to_datetime(df['release_date']).apply(lambda x: x.date())\n",
    "    json_columns = ['genres', 'keywords', 'production_countries', 'production_companies', 'spoken_languages']\n",
    "    for column in json_columns:\n",
    "        df[column] = df[column].apply(json.loads)\n",
    "    return df\n",
    "\n",
    "def load_tmdb_credits(path):\n",
    "    df = pd.read_csv(path)\n",
    "    json_columns = ['cast', 'crew']\n",
    "    for column in json_columns:\n",
    "        df[column] = df[column].apply(json.loads)\n",
    "    return df\n",
    "\n",
    "movies = load_tmdb_movies(\"tmdb_5000_movies.csv\")\n",
    "credits = load_tmdb_credits(\"tmdb_5000_credits.csv\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  Часть 2. Первичный анализ признаков"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Посмотрим что у нас из себя представляют данные."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "movies.head(3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Заключение:** Большинство признаков представляют собой json-контейнеры, которые ещё надо разворачивать и делать из них фичи."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(movies.shape)\n",
    "print(movies.info())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Заключение:** Практически все важные поля имеют значения - это хорошо"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "movies.describe()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "p = movies.original_language.value_counts()\n",
    "print(p.get_values())\n",
    "print(movies.original_language.unique())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# распределение голосов в зависимости от языка\n",
    "val_en_counts = movies[movies['original_language'] == 'en']['vote_average'].value_counts().sort_index()\n",
    "val_ja_counts = movies[movies['original_language'] == 'ja']['vote_average'].value_counts().sort_index()\n",
    "val_fr_counts = movies[movies['original_language'] == 'fr']['vote_average'].value_counts().sort_index()\n",
    "\n",
    "plt.title('Распределение значений рейтинга')\n",
    "plt.xlabel('vote_average'), plt.ylabel('Количество')\n",
    "plt.plot(val_en_counts.keys(),np.log(val_en_counts.values))\n",
    "plt.plot(val_ja_counts.keys(),np.log(val_ja_counts.values))\n",
    "plt.plot(val_fr_counts.keys(),np.log(val_fr_counts.values))\n",
    "plt.grid(True)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Заключение**. Очевидно, что англоязычных фильмов больше чем других, но распределение голосов похожее."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "p = movies.vote_average.value_counts().sort_index()\n",
    "\n",
    "plt.title('Распределение значений рейтинга')\n",
    "plt.xlabel('vote_average')\n",
    "plt.ylabel('Количество')\n",
    "plt.plot(p.keys(),p.values)\n",
    "plt.grid(True)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.scatter(x=np.log(movies.budget+1), y=np.log(movies.revenue+1), c=movies.vote_average)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# plt.scatter(x=np.log(movies.budget), y=np.log(movies.revenue), c=movies.vote_average)\n",
    "movies[ (movies['budget']>0) & (movies['revenue']>0) ].plot.scatter(x='budget', y='revenue', c='vote_average', figsize=(10, 10), s=45)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "movies[ movies['budget'] <=0].head(3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "movies[ movies['revenue'] <=0 ].head(3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Заключение**. Несмотря на то, что пропусков данных нет, в самих данных есть проблемы. TMDB ничего не знает о бюджете и доходах некоторых фильмов. (например, The Lovers, The Tuxedo). Видимо такие фильмы придётся в дальнейшем просто убирать из обучающей выборки.\n",
    "\n",
    "Для остальных фильмов наблюдается зависимость вложения и отдачи, но однозначно сказать что дорогой фильм будет очень востребован нельзя."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "movs = pd.concat([movies.budget, movies.revenue, movies.popularity, movies.vote_count, movies.vote_average], axis=1)\n",
    "#movs.vote_average = np.log(movs.vote_average)\n",
    "movs.popularity = np.log(movs.popularity+1)\n",
    "movs.vote_count = np.log(movs.vote_count+1)\n",
    "movs[ (movs.budget>0) & (movs.revenue>0)].plot.scatter(x='popularity', y='vote_average', figsize=(5, 5), c='vote_count')\n",
    "\n",
    "del movs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "**Заключение**. Сказать что популярный фильм будет иметь высоки рейтинг нельзя. Есть фильмы, которые не так популярны, но имеют высокий рейтинг."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "rel_date_time = pd.to_datetime(movies.release_date)\n",
    "rel_date_time[ rel_date_time > '1963-01-01' ].value_counts().plot(figsize=(20, 5))\n",
    "del rel_date_time"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "**Заключение**. TMDB в основном содержит фильмы 21 века."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Остальные признаки посмотрим, когда возьмём их из JSONa"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  Часть 5. Предобработка данных "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "Вытяним из JSONa все жанры, языки фильмов, страну производителя и сделаем OneHotEnconding вручную (кто знает как сделать это красивее напишите мне в Слаке)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "all_genres = []\n",
    "for i in range(0,movies.shape[0]):\n",
    "    all_genres.append([actor['name'] for actor in movies['genres'].iloc[i][:10]])\n",
    "all_genres = set(x for l in all_genres for x in l) # множество содержит только уникальные элементы\n",
    "\n",
    "genres = pd.DataFrame(columns=all_genres)\n",
    "for i in range(0,movies.shape[0]):\n",
    "    a = [actor['name'] for actor in movies['genres'].iloc[i][:10]]\n",
    "    for j in all_genres:\n",
    "        genres.at[i,j] = 0\n",
    "    for item in a:\n",
    "        genres.at[i,item] = 1\n",
    "\n",
    "genres.fillna(0, inplace=True)\n",
    "print(genres.shape)\n",
    "\n",
    "new_cols = 'genre_'+genres.columns\n",
    "genres.columns = new_cols\n",
    "# print(genres.info())\n",
    "# print(genres.head(5)) # для проверки\n",
    "# print(genres.tail(5)) # для проверки\n",
    "\n",
    "genres.to_csv('genres.csv')\n",
    "# genres = pd.read_csv('genres.csv')\n",
    "# genres = genres.drop('Unnamed: 0', axis=1)\n",
    "# for col in genres.columns:\n",
    "#     genres[col] = pd.to_numeric(genres[col], errors='coerce', downcast='unsigned')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Компаний очень много и комп медленно их обрабатывает, поэтому пока не трогаю\n",
    "# all_prod_companies = []\n",
    "# for i in range(0,movies.shape[0]):\n",
    "#     all_prod_companies.append([comp['id'] for comp in movies['production_companies'].iloc[i][:10]])\n",
    "# all_prod_companies = set(x for l in all_prod_companies for x in l)\n",
    "\n",
    "# prod_comps = pd.DataFrame(columns=all_prod_companies)\n",
    "# for i in range(0,movies.shape[0]):\n",
    "#     a = [comp['id'] for comp in movies['production_companies'].iloc[i][:10]]\n",
    "#     for j in all_prod_companies:\n",
    "#         prod_comps.at[i,j] = 0\n",
    "#     for item in a:\n",
    "#         prod_comps.at[i,item] = 1\n",
    "\n",
    "# prod_comps.fillna(0, inplace=True)\n",
    "# print(prod_comps.shape)\n",
    "# print(prod_comps.head(3))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "all_prod_countrs = []\n",
    "for i in range(0,movies.shape[0]):\n",
    "    all_prod_countrs.append([comp['iso_3166_1'] for comp in movies['production_countries'].iloc[i][:10]])\n",
    "all_prod_countrs = set(x for l in all_prod_countrs for x in l)\n",
    "print(all_prod_countrs)\n",
    "\n",
    "prod_countrs = pd.DataFrame(columns=all_prod_countrs)\n",
    "for i in range(0,movies.shape[0]):\n",
    "    a = [countr['iso_3166_1'] for countr in movies['production_countries'].iloc[i][:10]]\n",
    "    for j in all_prod_countrs:\n",
    "        prod_countrs.at[i,j] = 0\n",
    "    for item in a:\n",
    "        prod_countrs.at[i,item] = 1\n",
    "\n",
    "prod_countrs.fillna(0, inplace=True)\n",
    "new_cols = 'country_'+prod_countrs.columns\n",
    "prod_countrs.columns = new_cols\n",
    "\n",
    "print(prod_countrs.shape)\n",
    "# print(prod_countrs.head(3))\n",
    "prod_countrs.to_csv('prod_countrs.csv')\n",
    "# prod_countrs = pd.read_csv('prod_countrs.csv')\n",
    "# prod_countrs = prod_countrs.drop('Unnamed: 0', axis=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "all_spok_langs = []\n",
    "for i in range(0,movies.shape[0]):\n",
    "    all_spok_langs.append([comp['iso_639_1'] for comp in movies['spoken_languages'].iloc[i][:10]])\n",
    "all_spok_langs = set(x for l in all_spok_langs for x in l)\n",
    "# print(all_spok_langs)\n",
    "\n",
    "spok_langs = pd.DataFrame(columns=all_spok_langs)\n",
    "for i in range(0,movies.shape[0]):\n",
    "    a = [lang['iso_639_1'] for lang in movies['spoken_languages'].iloc[i][:10]]\n",
    "    for j in all_spok_langs:\n",
    "        spok_langs.at[i,j] = 0\n",
    "    for item in a:\n",
    "        spok_langs.at[i,item] = 1\n",
    "\n",
    "spok_langs.fillna(0, inplace=True)\n",
    "new_cols = 'country_'+spok_langs.columns\n",
    "spok_langs.columns = new_cols\n",
    "\n",
    "print(spok_langs.shape)\n",
    "# print(spok_langs.head(3))\n",
    "spok_langs.to_csv('spok_langs.csv')\n",
    "# prod_countrs = pd.read_csv('prod_countrs.csv')\n",
    "# prod_countrs = prod_countrs.drop('Unnamed: 0', axis=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "LabelEncoding оригинального языка:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.preprocessing import LabelEncoder\n",
    "\n",
    "labelEnc = LabelEncoder()\n",
    "movies.original_language = labelEnc.fit_transform(movies.original_language)\n",
    "# print(dict(enumerate(labelEnc.classes_)))\n",
    "# print(movies.original_language.head(3))      # для проверки"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Из даты релиза достаём год и месяц выпуска. Вдруг окажется что например, фильмы хорошо заходят перед новыми годом, а не перед новым учебным годом."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "temp_date_month = []\n",
    "temp_date = pd.to_datetime(movies.release_date)\n",
    "temp_date_data = [t.month for t in temp_date]\n",
    "movies['release_month'] = temp_date_data\n",
    "temp_date_data = [t.year for t in temp_date]\n",
    "movies['release_year'] = temp_date_data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Соединяем теперь все столбцы в один DataFrame"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "movies = pd.concat([movies, genres, prod_countrs, spok_langs], axis=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Удаляем все не нужные признаки: страница фильма, ИД в каталоге, оригинальное название, статус."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "movies.drop(['homepage', 'status', 'id', 'original_title', 'title', 'release_date'], axis=1, inplace=True)\n",
    "movies.drop(['genres', 'production_countries', 'spoken_languages'], axis=1, inplace=True)\n",
    "\n",
    "#   с чем я пока не умею работать\n",
    "movies.drop(['tagline', 'keywords', 'overview', 'production_companies'], axis=1, inplace=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Создаём наборы данных с признаками и целевым признаком:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "movies.columns[:50]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_data = movies.copy()\n",
    "x_data.drop('vote_average', axis=1, inplace=True)\n",
    "y_data = movies['vote_average']\n",
    "\n",
    "x_data.dropna(axis=0, inplace=True)\n",
    "y_data = y_data[x_data.index]\n",
    "\n",
    "data = pd.concat([x_data, y_data], axis=1)\n",
    "data.to_csv('data1.csv')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.model_selection import train_test_split\n",
    "\n",
    "x_train, x_test, y_train, y_test = train_test_split(x_data, y_data, test_size=0.33, random_state=43)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_train_f, x_test_f, y_train_f, y_test_f = train_test_split(x_data[(x_data.budget>0) & (x_data.revenue>0)], y_data[(x_data.budget>0) & (x_data.revenue>0)], test_size=0.33, random_state=43)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  Часть 3. Первичный визуальный анализ признаков"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**3. Первичный визуальный анализ данных (4 балла)**\n",
    "    (+) Построены визуализации (распределения признаков, матрица корреляций и т.д.), описана связь с анализом данным (п. 2). Присутствуют выводы;\n",
    "    (+/-) Построены визуализации (распределения признаков, матрица корреляций и т.д.). Присутствуют выводы с небольшими ошибками;\n",
    "    (-/+) Недостает важных визуализаций и/или присутствует много ошибок в выводах;\n",
    "    (-) Отсутствует."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# TODO Рейтинг фильмов, которые меняли своё название и не меняли."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "movies_log = movies[(movies['budget']>0) & (movies['revenue']>0)][['vote_average', 'popularity', 'revenue', 'budget', 'vote_count','runtime']].copy()\n",
    "movies_log.popularity = np.log(movies_log.popularity+1)\n",
    "movies_log.revenue = np.log(movies_log.revenue+1)\n",
    "movies_log.budget = np.log(movies_log.budget+1)\n",
    "movies_log.vote_count = np.log(movies_log.vote_count+1)\n",
    "# movies_log.vote_average = np.log(movies_log.vote_average+1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sns.pairplot(data=movies_log, hue='vote_average')#, vars=['vote_average', 'popularity', 'revenue', 'budget', 'vote_count'])#,'runtime'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(movies.release_month.value_counts())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "movies_log = movies[(movies['budget']>0) & (movies['revenue']>0)][['release_year', 'release_month', 'vote_average', 'popularity']].copy()\n",
    "movies_log.release_year = np.log(movies_log.release_year+1)\n",
    "movies_log.popularity = np.log(movies_log.popularity+1)\n",
    "sns.pairplot(data=movies_log, hue='release_month')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "f, ax = plt.subplots(nrows=1, ncols=2, figsize=(15, 3))\n",
    "corr = movies[['vote_average', 'popularity', 'revenue', 'runtime', 'budget', 'vote_count', 'release_year', 'release_month']].corr()\n",
    "sns.heatmap(corr, cmap='YlGnBu', annot=True, ax=ax[0], fmt='.1f')\n",
    "\n",
    "corr = movies[['vote_average', 'popularity', 'revenue', 'runtime', 'budget', 'vote_count', 'release_year', 'release_month']].corr(method='spearman')\n",
    "sns.heatmap(corr, cmap='YlGnBu', annot=True, ax=ax[1], fmt='.1f')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "corr = movies[['vote_average','genre_Action', 'genre_Drama', 'genre_Adventure', 'genre_Crime',\n",
    "        'genre_Western', 'genre_Comedy', 'genre_Mystery', 'genre_Music',\n",
    "        'genre_History', 'genre_Documentary', 'genre_Fantasy', 'genre_Romance',\n",
    "        'genre_Animation', 'genre_War', 'genre_Foreign', 'genre_TV Movie',\n",
    "        'genre_Science Fiction', 'genre_Family', 'genre_Horror',\n",
    "        'genre_Thriller']].corr()\n",
    "f, ax = plt.subplots(figsize=(10, 10))\n",
    "sns.heatmap(corr, cmap='YlGnBu', annot=True, ax=ax, fmt='.1f')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Заключение**. \n",
    "Что касается прогнозируемой величины: наиболее рейтинговые фильмы являются драмами. Рейтинг фильма сильно зависит от количества голосов, популярности и продолжительности.\n",
    "\n",
    "Просто наблюдения: семейный фильм скорее всего будет мультфильмом, драма скорее всего романтической и в историческом контексте, исторические фильмы чаще про войну, за популярные фильмы чаще всего голосуют. Наибольшее количество фильмов выходят в сентябре, что наверно не совсем логично. Например, в новогодние каникулы все отдыхают и обычно нечем заняться. С другой стороны это конец летнего сезона."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  Часть 4. Закономерности, \"инсайты\", особенности данных"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "Здесь описание того, что было показано до этого.\n",
    "\n",
    "Заключение по приведённым выше данным вполне очевидны. Например, семейный фильм - это значит что родители пойдут с детьми на мультфильмы (жанр - анимация). Далее как наблюдение - больше всего исторических фильмов о войне, нежели о великих достижениях и гениях своего времени.\n",
    "\n",
    "Также очевидно, что люди обсуждают и голосуют за те фильмы, на которые они ходили и возможно не раз или рассказали друзьям, что можно судит по кассовым сборам.\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  Часть 6. Создание новых признаков и описание этого процесса"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true,
    "scrolled": true
   },
   "source": [
    "отсутствует, жаль"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  Часть 7. Кросс-валидация, подбор параметров"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Построение пробной модели LinearRegression"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.linear_model import LinearRegression#, RidgeCV, LassoCV\n",
    "from sklearn.metrics import mean_absolute_error, mean_squared_error"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "lr = LinearRegression(n_jobs=-1)\n",
    "lr.fit(x_train, y_train)\n",
    "prediction = lr.predict(x_train)\n",
    "print('MAE',mean_absolute_error(y_train, prediction))\n",
    "print('MSE',mean_squared_error(y_train, prediction))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "lr = LinearRegression(n_jobs=-1)\n",
    "lr.fit(x_train_f, y_train_f)\n",
    "prediction = lr.predict(x_train_f)\n",
    "print('MAE',mean_absolute_error(y_train_f, prediction))\n",
    "print('MSE',mean_squared_error(y_train_f, prediction))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.model_selection import cross_val_predict"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "prediction = cross_val_predict(lr, x_train, y_train, cv=5, n_jobs=-1)\n",
    "print('MAE',mean_absolute_error(y_train, prediction))\n",
    "print('MSE',mean_squared_error(y_train, prediction))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "prediction = cross_val_predict(lr, x_train_f, y_train_f, cv=5, n_jobs=-1)\n",
    "print('MAE',mean_absolute_error(y_train_f, prediction))\n",
    "print('MSE',mean_squared_error(y_train_f, prediction))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "**Вывод**. Если в модель не закладывать фильмы, бюджет и доход которых нулевой (здесь больше всего шумов, см. выше), то даже линейная регрессия лучше работает. Это видно по MSE, т.к. она сильнее штрафует за большие ошибки (выбросы). Кросс-валидация этот результат не улучшает."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Выбираем такое количество признаков, которые описывают 98% всех решений и посмотрим на качество прогноза."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.decomposition import PCA\n",
    "#  из 9 домашки \n",
    "def plotPCA(pca, perct=90):\n",
    "    \"\"\"\n",
    "    График накопленного процента объясненной дисперсии по компонентам\n",
    "    \"\"\"\n",
    "    features = range(pca.n_components_)\n",
    "    variance = np.cumsum(np.round(pca.explained_variance_ratio_, decimals=4)*100)\n",
    "    plt.figure(figsize=(15, 7))\n",
    "    plt.bar(features, variance)\n",
    "    \n",
    "    # дополнительно отметим уровень, при котором объяснены 90% дисперсии\n",
    "    plt.hlines(y = perct, xmin=0, xmax=len(features), linestyles='dashed', colors='red')\n",
    "    \n",
    "    plt.xlabel('PCA components')\n",
    "    plt.ylabel('variance')\n",
    "    plt.xticks(features)\n",
    "    plt.show()\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.preprocessing import StandardScaler\n",
    "\n",
    "scaler = StandardScaler()\n",
    "scaler.fit(x_train)\n",
    "x_train_scaled = scaler.transform(x_train)\n",
    "x_test_scaled = scaler.transform(x_test)\n",
    "prediction = cross_val_predict(lr, x_train_scaled, y_train, cv=5, n_jobs=-1)\n",
    "print('MAE',mean_absolute_error(y_train, prediction))\n",
    "print('MSE',mean_squared_error(y_train, prediction))\n",
    "\n",
    "pca = PCA()\n",
    "pca.fit(x_train_scaled, y_train)\n",
    "plotPCA(pca)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.preprocessing import StandardScaler\n",
    "\n",
    "scaler = StandardScaler()\n",
    "scaler.fit(x_train)\n",
    "x_train_scaled = scaler.transform(x_train_f)\n",
    "x_test_scaled = scaler.transform(x_test_f)\n",
    "prediction = cross_val_predict(lr, x_train_scaled, y_train_f, cv=5, n_jobs=-1)\n",
    "print('MAE',mean_absolute_error(y_train_f, prediction))\n",
    "print('MSE',mean_squared_error(y_train_f, prediction))\n",
    "\n",
    "pca = PCA()\n",
    "pca.fit(x_train_scaled, y_train_f)\n",
    "plotPCA(pca)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "features = range(pca.n_components_)\n",
    "variance = np.cumsum(np.round(pca.explained_variance_ratio_, decimals=4)*100)\n",
    "print(variance[16*9+5], features[16*9+5])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pca = PCA(n_components=144)\n",
    "pca.fit(x_train_scaled, y_train_f)\n",
    "pca_features_train = pca.transform(x_train_scaled)\n",
    "pca_features_test = pca.transform(x_test_scaled)\n",
    "lr.fit(pca_features_train, y_train_f)\n",
    "prediction = lr.predict(pca_features_test)\n",
    "print('MAE',mean_absolute_error(y_test_f, prediction))\n",
    "print('MSE',mean_squared_error(y_test_f, prediction))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Заключение.** Уменьшение количества признаков сильно картину не улучшает, возможно это из-за масштабирования. (масштабирование коэффициентов не улучшает картину, либо я где-то ошибся, т.к. МАЕ и MSE были огромными)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Построение модели LassoCV"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.linear_model import LassoCV"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "LS_CV = LassoCV(cv=5, n_jobs=-1)\n",
    "LS_CV.fit(x_train_f,y_train_f)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "prediction = LS_CV.predict(x_train_f)\n",
    "print('MAE',mean_absolute_error(y_train_f, prediction))\n",
    "print('MSE',mean_squared_error(y_train_f, prediction))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Построение модели RidgeCV"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.linear_model import RidgeCV"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "Rg_CV = RidgeCV(cv=5)\n",
    "Rg_CV.fit(x_train_f,y_train_f)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "prediction = Rg_CV.predict(x_train_f)\n",
    "print('MAE',mean_absolute_error(y_train_f, prediction))\n",
    "print('MSE',mean_squared_error(y_train_f, prediction))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "score_list = [0.01, 0.1, 1, 10, 100, 1000 ] #[ 'svd', 'eigen'] #['explained_variance', 'neg_mean_absolute_error', 'neg_mean_squared_error','neg_mean_squared_log_error','neg_median_absolute_error','r2']\n",
    "# for score in score_list:\n",
    "Rg_CV = RidgeCV(cv=5, alphas=score_list)\n",
    "Rg_CV.fit(x_train_f,y_train_f)\n",
    "prediction = Rg_CV.predict(x_train_f)\n",
    "print('MAE',mean_absolute_error(y_train_f, prediction), 'MSE',mean_squared_error(y_train_f, prediction))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Построение модели ElasticNet"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.linear_model import ElasticNet\n",
    "from sklearn.model_selection import GridSearchCV"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "alphas = [.01, .05, .1, .2, 1.0]\n",
    "l1_ratios = np.linspace(.05, .15, 10)\n",
    "# alphas = [0.1, 1.0, 10]\n",
    "# l1_ratios = np.linspace(.1, .9, 3)\n",
    "el_net = ElasticNet()\n",
    "parameters = {'alpha':alphas, 'l1_ratio':l1_ratios}\n",
    "grid = GridSearchCV(el_net, param_grid=parameters, scoring='mean_absolute_error' ,verbose=1, cv=5, return_train_score=1, n_jobs=-1)\n",
    "grid.fit(x_train_f, y_train_f)\n",
    "print(grid.best_score_)\n",
    "print(grid.best_estimator_)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "el_net_best = grid.best_estimator_\n",
    "prediction = el_net_best.predict(x_train_f)\n",
    "print(el_net_best.score(x_train_f, y_train_f))\n",
    "print('MAE',mean_absolute_error(y_train_f, prediction))\n",
    "print('MSE',mean_squared_error(y_train_f, prediction))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Заключение.** Из рассмотренных моделей ElasticNet и RidgeCV показали хорошие результаты. Правда у ElasticNet коэффициент детерминации маловат и коэффициент `l1_ratio` такой что он по сути является RidgeCV (т.е. применятся Л2-регуляризация).  Обратимся к кривым валидации для проверки. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.ensemble import RandomForestRegressor\n",
    "estimators = np.arange(5,60,20)\n",
    "min_samples_leaf = np.arange(5,20,5)\n",
    "parameters = {'n_estimators':estimators, 'min_samples_leaf':min_samples_leaf}\n",
    "rfrr = RandomForestRegressor(criterion='mae', n_jobs=-1)\n",
    "grid = GridSearchCV(rfrr, param_grid=parameters, scoring='mean_absolute_error', verbose=1, cv=5, return_train_score=1, n_jobs=-1)\n",
    "grid.fit(x_train_f, y_train_f)\n",
    "print(grid.best_score_)\n",
    "print(grid.best_estimator_)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "rfrr_best = grid.best_estimator_\n",
    "prediction = rfrr_best.predict(x_train_f)\n",
    "print('MAE',mean_absolute_error(y_train_f, prediction))\n",
    "print('MSE',mean_squared_error(y_train_f, prediction))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Заключение.** Лес дал неплохой результат."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.ensemble import AdaBoostRegressor\n",
    "\n",
    "estimators = np.arange(5,60,20)\n",
    "loss = ['linear', 'square', 'exponential']\n",
    "parameters = {'n_estimators':estimators, 'loss':loss}\n",
    "abrr = AdaBoostRegressor(random_state=42)\n",
    "grid = GridSearchCV(abrr, param_grid=parameters, scoring='mean_absolute_error', verbose=1, cv=5, return_train_score=1, n_jobs=-1)\n",
    "grid.fit(x_train_f, y_train_f)\n",
    "print(grid.best_score_)\n",
    "print(grid.best_estimator_)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "abrr_best = grid.best_estimator_\n",
    "prediction = abrr_best.predict(x_train_f)\n",
    "print('MAE',mean_absolute_error(y_train_f, prediction))\n",
    "print('MSE',mean_squared_error(y_train_f, prediction))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  Часть 8. Построение кривых валидации и обучения "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.model_selection import learning_curve"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# from http://scikit-learn.org/stable/auto_examples/model_selection/plot_learning_curve.html#sphx-glr-auto-examples-model-selection-plot-learning-curve-py\n",
    "def plot_learning_curve(estimator, title, X, y, ylim=None, cv=None,\n",
    "                        n_jobs=1, train_sizes=np.linspace(.1, 1.0, 5)):\n",
    "    \"\"\"\n",
    "    Generate a simple plot of the test and training learning curve.\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    estimator : object type that implements the \"fit\" and \"predict\" methods\n",
    "        An object of that type which is cloned for each validation.\n",
    "\n",
    "    title : string\n",
    "        Title for the chart.\n",
    "\n",
    "    X : array-like, shape (n_samples, n_features)\n",
    "        Training vector, where n_samples is the number of samples and\n",
    "        n_features is the number of features.\n",
    "\n",
    "    y : array-like, shape (n_samples) or (n_samples, n_features), optional\n",
    "        Target relative to X for classification or regression;\n",
    "        None for unsupervised learning.\n",
    "\n",
    "    ylim : tuple, shape (ymin, ymax), optional\n",
    "        Defines minimum and maximum yvalues plotted.\n",
    "\n",
    "    cv : int, cross-validation generator or an iterable, optional\n",
    "        Determines the cross-validation splitting strategy.\n",
    "        Possible inputs for cv are:\n",
    "          - None, to use the default 3-fold cross-validation,\n",
    "          - integer, to specify the number of folds.\n",
    "          - An object to be used as a cross-validation generator.\n",
    "          - An iterable yielding train/test splits.\n",
    "\n",
    "        For integer/None inputs, if ``y`` is binary or multiclass,\n",
    "        :class:`StratifiedKFold` used. If the estimator is not a classifier\n",
    "        or if ``y`` is neither binary nor multiclass, :class:`KFold` is used.\n",
    "\n",
    "        Refer :ref:`User Guide <cross_validation>` for the various\n",
    "        cross-validators that can be used here.\n",
    "\n",
    "    n_jobs : integer, optional\n",
    "        Number of jobs to run in parallel (default 1).\n",
    "    \"\"\"\n",
    "    plt.figure()\n",
    "    plt.title(title)\n",
    "    if ylim is not None:\n",
    "        plt.ylim(*ylim)\n",
    "    plt.xlabel(\"Training examples\")\n",
    "    plt.ylabel(\"Score\")\n",
    "    train_sizes, train_scores, test_scores = learning_curve(\n",
    "        estimator, X, y, cv=cv, n_jobs=n_jobs, train_sizes=train_sizes, scoring='mean_absolute_error')\n",
    "    train_scores_mean = np.mean(train_scores, axis=1)\n",
    "    train_scores_std = np.std(train_scores, axis=1)\n",
    "    test_scores_mean = np.mean(test_scores, axis=1)\n",
    "    test_scores_std = np.std(test_scores, axis=1)\n",
    "    plt.grid()\n",
    "\n",
    "    plt.fill_between(train_sizes, train_scores_mean - train_scores_std,\n",
    "                     train_scores_mean + train_scores_std, alpha=0.1,\n",
    "                     color=\"r\")\n",
    "    plt.fill_between(train_sizes, test_scores_mean - test_scores_std,\n",
    "                     test_scores_mean + test_scores_std, alpha=0.1, color=\"g\")\n",
    "    plt.plot(train_sizes, train_scores_mean, 'o-', color=\"r\",\n",
    "             label=\"Training score\")\n",
    "    plt.plot(train_sizes, test_scores_mean, 'o-', color=\"g\",\n",
    "             label=\"Cross-validation score\")\n",
    "\n",
    "    plt.legend(loc=\"best\")\n",
    "    return plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plot_learning_curve(lr, 'LR learning curves', x_train, y_train, ylim=None, cv=5,\n",
    "                        n_jobs=-1, train_sizes=np.linspace(.1, 1.0, 5))\n",
    "plot_learning_curve(lr, 'LR learning curves (filtered data)', x_train_f, y_train_f, ylim=None, cv=5,\n",
    "                        n_jobs=-1, train_sizes=np.linspace(.1, 1.0, 5))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Заключение.** Судя по кривой обучения увеличение данных хорошо влияет, т.к. уменьшается вариация (varience)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plot_learning_curve(LS_CV, 'LS learning curves', x_train_f, y_train_f, ylim=None, cv=5,\n",
    "                        n_jobs=-1, train_sizes=np.linspace(.1, 1.0, 5))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Заключение.** Использовать эту модель не стоит, т.к. очень большое отклонение; а близкое расположение кривых при увеличении обучающей выборки говорит о высоком смещении оценки."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plot_learning_curve(Rg_CV, 'Rg learning curves', x_train_f, y_train_f, ylim=None, cv=5,\n",
    "                        n_jobs=-1, train_sizes=np.linspace(.01, 1.0, 10))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Заключение.** Тут выглядит очень непонятно. Вроде как не надо много данных и модель сразу же получает хорошую оценку. Масштабирование с 0,01 до 0,2 размера выборки ничего хорошего не показало. Поэтому думаю оставить эту модель ии посмотреть, что будет на тесте. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "el_net_best = grid.best_estimator_\n",
    "plot_learning_curve(el_net_best, 'el_net_best learning curves', x_train_f, y_train_f, ylim=None, cv=5,\n",
    "                        n_jobs=-1, train_sizes=np.linspace(.01, .3, 5))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.model_selection import cross_val_score\n",
    "alphas = np.linspace(0.01, 2.0, 15) #[.01, .05, .1, .2, 1.0]\n",
    "mse_array = []\n",
    "mae_array = []\n",
    "scores_array = []\n",
    "scores_std_array = []\n",
    "\n",
    "for alph in alphas:\n",
    "    el_net_temp = ElasticNet(alpha=alph, l1_ratio=0.08333)\n",
    "    el_net_temp.fit(x_train_f, y_train_f)\n",
    "    \n",
    "    scores = cross_val_score(el_net_temp, x_train_f, y_train_f, scoring='mean_absolute_error', cv=5, n_jobs=-1)\n",
    "    prediction = el_net_temp.predict(x_train_f)\n",
    "    \n",
    "    scores_array.append(scores.mean())\n",
    "    scores_std_array.append(scores.std())    \n",
    "    mae_array.append(mean_absolute_error(y_train_f, prediction))\n",
    "    mse_array.append(mean_squared_error(y_train_f, prediction))\n",
    "#     print(alph, scores, 'MAE',mean_absolute_error(y_train_f, prediction), 'MSE',mean_squared_error(y_train_f, prediction))\n",
    "\n",
    "plt.figure()\n",
    "plt.title('Alpha - regularization')\n",
    "plt.xlabel(\"Alpha\")\n",
    "plt.ylabel(\"Score\")\n",
    "plt.grid()\n",
    "plt.fill_between(alphas, -np.asarray(scores_array) - np.asarray(scores_std_array),\n",
    "                 -np.asarray(scores_array) + np.asarray(scores_std_array), alpha=0.1,\n",
    "                 color=\"r\")\n",
    "plt.plot(alphas, -np.asarray(scores_array), 'o-', color=\"r\", label=\"Cross-validation score\")\n",
    "plt.plot(alphas, mae_array, 'o-', color=\"g\", label=\"Train score\")\n",
    "plt.legend(loc=\"best\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Заключение.** По валидационной кривой очень похоже на высокое смещение оценки. Как интерпретировать вторую кривую (скор от регуляризации) не знаю. Думал что тоже покажет мне или смещение или разброс, но не дало."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plot_learning_curve(rfrr_best, 'RandomForest learning curves', x_train_f, y_train_f, ylim=None, cv=5,\n",
    "                        n_jobs=-1, train_sizes=np.linspace(.1, 1.0, 5))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plot_learning_curve(abrr_best, 'RandomForest learning curves', x_train_f, y_train_f, ylim=None, cv=5,\n",
    "                        n_jobs=-1, train_sizes=np.linspace(.1, 1.0, 5))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Заключение.** Более привычный рисунок для проверки. Чем больше данных тем лучше, highbias. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  Часть 9. Прогноз для тестовой или отложенной выборки"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true,
    "scrolled": true
   },
   "source": [
    "### LinearRegression"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "lr = LinearRegression(n_jobs=-1)\n",
    "lr.fit(x_train, y_train)\n",
    "prediction = lr.predict(x_test)\n",
    "print('MAE',mean_absolute_error(y_test, prediction))\n",
    "print('MSE',mean_squared_error(y_test, prediction))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "По отфильтрованной обучающей выборке:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "lr.fit(x_train_f, y_train_f)\n",
    "prediction = lr.predict(x_test)\n",
    "print('MAE',mean_absolute_error(y_test, prediction))\n",
    "print('MSE',mean_squared_error(y_test, prediction))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Остальные"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "LS_CV = LassoCV(cv=5, n_jobs=-1)\n",
    "LS_CV.fit(x_train_f, y_train_f)\n",
    "prediction = LS_CV.predict(x_test)\n",
    "print('MAE',mean_absolute_error(y_test, prediction))\n",
    "print('MSE',mean_squared_error(y_test, prediction))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "Rg_CV = RidgeCV(cv=5)\n",
    "Rg_CV.fit(x_train_f, y_train_f)\n",
    "prediction = Rg_CV.predict(x_test)\n",
    "print('MAE',mean_absolute_error(y_test, prediction))\n",
    "print('MSE',mean_squared_error(y_test, prediction))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "el_net_best = ElasticNet(alpha=0.01, copy_X=True, fit_intercept=True,\n",
    "      l1_ratio=0.083333333333333329, max_iter=1000, normalize=False,\n",
    "      positive=False, precompute=False, random_state=None,\n",
    "      selection='cyclic', tol=0.0001, warm_start=False)\n",
    "el_net_best.fit(x_train_f, y_train_f)\n",
    "prediction = Rg_CV.predict(x_test)\n",
    "print('MAE',mean_absolute_error(y_test, prediction))\n",
    "print('MSE',mean_squared_error(y_test, prediction))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "rfrr = RandomForestRegressor(bootstrap=True, criterion='mae', max_depth=None,\n",
    "           max_features='auto', max_leaf_nodes=None,\n",
    "           min_impurity_decrease=0.0, min_impurity_split=None,\n",
    "           min_samples_leaf=5, min_samples_split=2,\n",
    "           min_weight_fraction_leaf=0.0, n_estimators=45, n_jobs=-1,\n",
    "           oob_score=False, random_state=None, verbose=0, warm_start=False)\n",
    "rfrr.fit(x_train_f, y_train_f)\n",
    "prediction = rfrr.predict(x_test)\n",
    "print('MAE',mean_absolute_error(y_test, prediction))\n",
    "print('MSE',mean_squared_error(y_test, prediction))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "abrr = AdaBoostRegressor(base_estimator=None, learning_rate=1.0, loss='linear',\n",
    "         n_estimators=25, random_state=42)\n",
    "abrr.fit(x_train_f, y_train_f)\n",
    "prediction = abrr.predict(x_test)\n",
    "print('MAE',mean_absolute_error(y_test, prediction))\n",
    "print('MSE',mean_squared_error(y_test, prediction))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Заключение**. Оценки как отфильтрованные, так и не отфильтрованные вполне соответствуют значениям метрик на обучающей выборке. Победил Случайный лес.\n",
    "\n",
    "Я выбирал бы случайный лес или линейную регрессию. Первая как-то надёжнее, но вторая проще, разница в качестве между ними небольшая."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  Часть 10. Оценка модели с описанием выбранной метрики"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true,
    "scrolled": true
   },
   "source": [
    "Так как не понятно было изначально к чему можно было прийти я пошёл классическим путём: выбрать что-то простое (линейная регрессия) и серебрянную пулю (Случайный лес). Собственно говоря они и хорошо зашли. Если честно, то не знаю что выбрать MSE или MAE. Я думаю что MAE говорит о точности оценки, а MSE что-то вроде разброса.\n",
    "\n",
    "В целом я результатом доволен, не смотря на то, что я не использую данные об описании (можно было бы построить новые фичи, но как на это время на оставил), ключевые слова или кинокомпании. Даже без этого модели (Лес и ЛР) дают оценку с ошибкой в 100/10*0.58 = 5,8% и 6,7% соответственно. Пожалуй это и было бы основной метрикой, чем меньше процент ошибки, тем лучше - как инженерный подход."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Часть 11. Выводы "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true,
    "scrolled": true
   },
   "source": [
    "Теперь мы можем предсказывать рейтинг фильма. Это может нам понадобится при проведении подготовительных работ над фильмом - его  описание, закладывать бюджет и т.п. Почему результат такой - думаю, потому что основные признаки как популярность и количество голосов влияют больше остальных, да и фильтрация по бюджету и доходу - это было важно."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
